using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;


namespace Prototype_Game_1
{
    /// <summary>
    /// This is a game component that implements IUpdateable.
    /// </summary>
    public class SpriteManager : Microsoft.Xna.Framework.DrawableGameComponent
    {
        private SpriteBatch spriteBatch;
        private UserBasketSprite player;
        private List<Sprite> spriteList = new List<Sprite>();
        private List<string> circles;
        
        private int nextCircleGroupSpawn = 500;
        private const int spawnTime = 500;
        private int nextCircleToCollectSpawnTime = 7000;
        private const int CircleToCollectSpawnTime = 7000;

        private int score = 0;
        private SpriteFont font;
        private Texture2D circleToCollect;
        private string circleToCollectName;

        public SpriteManager(Game game, SpriteFont font, List<string> circles)
            : base(game)
        {
            this.font = font;
            this.circles = circles;
        }

        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public override void Initialize()
        {
            // TODO: Add your initialization code here

            base.Initialize();
        }

        protected override void LoadContent( )
        {
            List<Texture2D> userBasketSprites = new List<Texture2D>();
            spriteBatch = new SpriteBatch(Game.GraphicsDevice);
            userBasketSprites.Add(Game.Content.Load<Texture2D>(@"Images/waste-paper-basket-1"));
            userBasketSprites.Add(Game.Content.Load<Texture2D>(@"Images/waste-paper-basket-left-1"));
            userBasketSprites.Add(Game.Content.Load<Texture2D>(@"Images/waste-paper-basket-down-1"));
            userBasketSprites.Add(Game.Content.Load<Texture2D>(@"Images/waste-paper-basket-right-1"));
            
            player = new UserBasketSprite("player",
            Game.Content.Load<Texture2D>(@"Images/waste-paper-basket-1"),
            Vector2.Zero, new Point(128, 128), 30, new Vector2(8, 8), userBasketSprites);

            spriteList.AddRange(createSprites());

            font = Game.Content.Load<SpriteFont>(@"fonts\score");
            circleToCollect = chooseRandomCircleToCollect();
            
            base.LoadContent();
        }

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            // Update player
            player.Update(gameTime, Game.Window.ClientBounds);
            
            // Update all sprites
            nextCircleGroupSpawn -= gameTime.ElapsedGameTime.Milliseconds;

            //check if it's time to create new sprites
            if (nextCircleGroupSpawn < 0)
            {
                //reset spawn time and create new sprites
                nextCircleGroupSpawn = spawnTime;
                spriteList.AddRange(createSprites());
            }
            else
            {
                //update each sprite
                for (int i = spriteList.Count - 1; i >= 0; i--)
                {
                    Sprite s = spriteList.ElementAt(i);
                    s.Update(gameTime, Game.Window.ClientBounds);

                    //remove sprites that are out of bounds
                    if (s.Position.X > Game.Window.ClientBounds.Width || s.Position.X < 0)
                        spriteList.RemoveAt(i);

                    if (s.Position.Y > Game.Window.ClientBounds.Height || s.Position.Y < 0)
                        spriteList.RemoveAt(i);

                    //check if player intersects circles according to the player's current direction
                    if (s.collisionRect.Intersects(player.collisionRect))
                    {
                        if (player.CurrentTexture.Equals(UserBasketSprite.Texture.up) && s.direction.X == 0 && s.direction.Y > 0)
                        {
                            if(s.Name.Equals(circleToCollectName))
                                score += 10;
                            spriteList.RemoveAt(i);
                        }
                        else if (player.CurrentTexture.Equals(UserBasketSprite.Texture.left) && s.direction.X > 0 && s.direction.Y == 0)
                        {
                            if (s.Name.Equals(circleToCollectName))
                                score += 10;
                            spriteList.RemoveAt(i);
                        }
                        else if (player.CurrentTexture.Equals(UserBasketSprite.Texture.down) && s.direction.X == 0 && s.direction.Y < 0)
                        {
                            if (s.Name.Equals(circleToCollectName))
                                score += 10;
                            spriteList.RemoveAt(i);
                        }
                        else if (player.CurrentTexture.Equals(UserBasketSprite.Texture.right) && s.direction.X < 0 && s.direction.Y == 0)
                        {
                            if (s.Name.Equals(circleToCollectName))
                                score += 10;
                            spriteList.RemoveAt(i);
                        }
                    }
                }
            }
            
            nextCircleToCollectSpawnTime -= gameTime.ElapsedGameTime.Milliseconds;

            //check if it's time to change collect circle
            if (nextCircleToCollectSpawnTime < 0)
            {
                //reset spawn time and create new sprites
                nextCircleToCollectSpawnTime = CircleToCollectSpawnTime;
                circleToCollect = chooseRandomCircleToCollect();
            }

            base.Update(gameTime);
        }

        public override void Draw(GameTime gameTime)
        {
            spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend);
            // Draw Score
            spriteBatch.DrawString(font, "Score: " + score, new Vector2(10, 10), Color.White);
            spriteBatch.DrawString(font, "Circle to Collect: ", new Vector2(200, 10), Color.White);
            spriteBatch.Draw(circleToCollect, new Vector2(430, 8), Color.White);
            // Draw the player
            player.Draw(gameTime, spriteBatch);
            // Draw all sprites
            foreach (Sprite s in spriteList)
                s.Draw(gameTime, spriteBatch);
            spriteBatch.End( );

            base.Draw(gameTime);
        }

        private List<Sprite> createSprites()
        {
            List<Sprite> sprites = new List<Sprite>();
            List<int> Xpositions = new List<int>();
            List<int> Ypositions = new List<int>();
            for (int i = 60; i < Game.Window.ClientBounds.Width - 60; i+=45)
            {
                Xpositions.Add(i);
            }

            for (int i = 60; i < Game.Window.ClientBounds.Height - 60; i += 45)
            {
                Ypositions.Add(i);
            }

            Random r = new Random();
            
            int chosenCircle = r.Next(0, 8);
            Vector2 position = chooseRandomPosition(ref Xpositions, ref Ypositions);
            Vector2 speed = chooseRandomSpeed(position);
            string circleName = circles.ElementAt(chosenCircle);

            sprites.Add(new AutomatedColorSprite(circleName,
            Game.Content.Load<Texture2D>(@"Images/" + circleName),
            position, new Point(45, 45), 30, speed));
                
            
            return sprites;
        }

        private Vector2 chooseRandomSpeed(Vector2 position)
        {
            Random r = new Random();
            Vector2 speed = new Vector2();
            if (position.Y == 0)
            {
                speed.X = 0;
                speed.Y = r.Next(1, 7);
            }
            if (position.X == 0)
            {
                speed.X = r.Next(1, 7);
                speed.Y = 0;
            }
            if (position.Y == Game.Window.ClientBounds.Height)
            {
                speed.X = 0;
                speed.Y = -r.Next(1, 7);
            }
            if (position.X == Game.Window.ClientBounds.Width)
            {
                speed.X = -r.Next(1, 7);
                speed.Y = 0;
            }
            return speed;
        }

        private Vector2 chooseRandomPosition(ref List<int> Xpositions, ref List<int> Ypositions)
        {
            Random r = new Random();
            Vector2 position = new Vector2();

            int randomDirection = r.Next(0, 4);

            if (randomDirection == 0)
            {
                int Xpos = r.Next(Xpositions.Count);
                position.X = Xpositions.ElementAt(Xpos);
                Xpositions.RemoveAt(Xpos);
                position.Y = 0;
            }
            if (randomDirection == 1)
            {
                int Ypos = r.Next(Ypositions.Count);
                position.Y = Ypositions.ElementAt(Ypos);
                Ypositions.RemoveAt(Ypos);
                position.X = 0;
            }
            if (randomDirection == 2)
            {
                int Xpos = r.Next(Xpositions.Count);
                position.X = Xpositions.ElementAt(Xpos);
                Xpositions.RemoveAt(Xpos);
                position.Y = Game.Window.ClientBounds.Height;
            }
            if (randomDirection == 3)
            {
                int Ypos = r.Next(Ypositions.Count);
                position.Y = Ypositions.ElementAt(Ypos);
                Ypositions.RemoveAt(Ypos);
                position.X = Game.Window.ClientBounds.Width;
            }
            return position;
        }

        private Texture2D chooseRandomCircleToCollect()
        {
            Random r = new Random();
            int chosenCircle = r.Next(0, 8);
            circleToCollectName = circles.ElementAt(chosenCircle);
            Texture2D chosenCircleSprite = Game.Content.Load<Texture2D>(@"Images/" + circleToCollectName);
            return chosenCircleSprite;
        }

        public int Score
        {
            get { return score; }
        }
    }
}
